// Copyright 2022 jeff.li. and/or its affiliates.

#pragma once

#include <string>

#include <tbir/runtime/container/itertor_ref.h>
#include <tbir/runtime/container/string.h>
#include <tbir/runtime/container/unicode.h>
#include <tbir/runtime/object.h>
#include <tbir/runtime/runtime_value.h>

namespace tbir::runtime {

    class FileNode;

    class File : public ObjectRef {
    public:
        using ContainerType = FileNode;
        static constexpr bool _type_is_nullable = false;  // disable nullptr for performance

        // constructors
        /*!
         * \brief constructor
         */
        explicit File(const Unicode &path,
                      const Unicode &mode = U"r",
                      const Unicode &encoding = U"utf-8");

        /*!
         * \brief move constructor
         * \param other source
         */
        File(File &&other) noexcept;

        /*!
         * \brief copy constructor
         */
        File(const File &other) noexcept = default;

        /*!
         * \brief constructor from pointer
         * \param n the container pointer
         */
        explicit File(ObjectPtr <Object> n) noexcept;

        /*!
         * \brief move assign operator
         * \param other The source of assignment
         * \return reference to self.
         */
        File &operator=(File &&other) noexcept;

        /*!
         * \brief copy assign operator
         */
        File &operator=(const File &other) noexcept = default;

        const FileNode *operator->() const;

        const FileNode *get() const;

    public:
        // method for python
        bool HasNext() const;

        string_view path() const;

        String ReadString(int64_t size = -1) const;

        Unicode ReadUnicode(int64_t size = -1) const;

        RTValue Read(int64_t size = -1) const;

        String ReadLineString() const;

        Unicode ReadLineUnicode() const;

        List ReadLines() const;

        RTValue Next() const;

        RTValue Next(bool *has_next) const;

        RTView NextView(bool *has_next, RTValue *holder_or_null) const;

        void close() const;
    };

    namespace TypeIndex {
        template<>
        struct type_index_traits<File> {
            static constexpr int32_t value = kRuntimeFile;
        };
    }  // namespace TypeIndex

    template<>
    bool IsConvertible<File>(const Object *node);

    std::ostream &operator<<(std::ostream &os, File const &n);

}  // namespace tbir::runtime
